var rword = /[^, ]+/g;
/**
 * 作用域内的唯一id字符串
 * @memberOf commonUtil
 * @return {string}
 */

var $$uid = ["0", "0", "0"];

function nextUid() {
    var index = $$uid.length;
    var digit;
    while (index) {
        index--;
        digit = $$uid[index].charCodeAt(0);
        if (digit == 57 /*'9'*/) {
            $$uid[index] = 'A';
            return $$uid.join('');
        }
        if (digit == 90 /*'Z'*/) {
            $$uid[index] = '0';
        } else {
            $$uid[index] = String.fromCharCode(digit + 1);
            return $$uid.join('');
        }
    }
    $$uid.unshift('0');
    return $$uid.join('');
}
/**
 * 发布订阅系统
 * @namespace pubsub
 */
/**
 * 创建一个发布订阅系统
 * @memberOf pubsub
 * @return {object} 独立的发布订阅系统
 */
function initPB() {
    /**
     * 进入channel，channel如果不存在，则创建
     * @param  {array|string} queues 传入数组或者"ab,v,d"字符串，当传参为 "$all"/["$all"]时，表示选择所有channel
     * @return {object}        返回Observable关于订阅的操作方法
     */
    function pb(queues) {
        var $que = [],
            jcQueue = pb.fn.$jcQueue;
        //var re = {};

        if (typeof queues === 'string') {
            queues = queues.match(rword)
        }
        if (queues[0] === '$all') {
            if (Object.keys) {
                $que = Object.keys(jcQueue);
            } else {
                var key
                for (key in jcQueue) {
                    $que.push(key);
                }
            }
        } else {
            // TODO:重复值
            queues.forEach(function (q) {
                $que.push(jcQueue.hasOwnProperty(q) ? jcQueue[q] : jcQueue[q] = {})
            })

        }
        pb.fn.$que = $que;
        pb.fn.$channel = queues;

        return pb.fn
    }

    pb.fn = {
        /**
         * 发布消息
         *
         * @param  {string} eventName
         * @param  {object|string} data
         * @return {boolean}
         */
        publish: function (eventName, data) {
            var eventTriggered = false
            for (var i = 0; i < this.$que.length; i++) {
                var q = this.$que[i]
                if (q[eventName] && q[eventName].length > 0) {
                    //队列在执行的时候，可能会遭遇到解绑自身绑定函数，导致后面相连的没有被执行
                    q[eventName].concat().forEach(function (fn) {
                        fn(data, eventName);
                    })
                    eventTriggered = true
                }
            }
            return eventTriggered
        },
        /**
         * 解除订阅，可解除整个管道，或具体到一个具体函数
         * @param  {string} eventName
         * @param  {string=} fnName    可选的 function name
         */
        unbind: function (eventName, fnName) {
            if (eventName === '$all') {
                for (var i = 0, channelName; channelName = this.$channel[i++];)
                    if (channelName in this.$jcQueue) {
                        delete this.$jcQueue[channelName]
                    }
            }
            this.$que.forEach(function (q) {
                if (fnName) {
                    var newFunc = []
                    q[eventName].forEach(function (fn, index, arr) {
                        if (fn.fnName !== fnName)
                            newFunc.push(fn)
                    })
                    q[eventName] = newFunc
                    if (!q[eventName].length) {
                        delete q[eventName]
                    }
                } else {
                    delete q[eventName]
                }
            })
        },
        /**
         * 通过正则，获取匹配的eventName
         *
         * @param  {Object} reg
         * @return {Array}
         */
        eventNamesWithReg: function (reg) {
            var re = [];
            if (typeof reg === 'string')
                reg = new RegExp(reg)
            this.$que.forEach(function (queue) {
                for (var eventName in queue) {
                    if (reg.test(eventName))
                        re.push(eventName)
                }
            })
            return re
        },
        /**
         * 订阅事件，函数名称可不填,函数名称也可以用来归类
         * @param  {string }   eventName
         * @param  {string=}   fnName  option
         * @param  {function} fn
         * @return {this}
         */
        bind: function (eventName, fnName, fn) {
            // TODO 重复的剔除
            if (fn === undefined) {
                fn = fnName
            } else {
                fn.fnName = fnName
            }
            this.$que.forEach(function (que) {
                var eventArr = que[eventName];
                if (!eventArr)
                    eventArr = que[eventName] = [];
                eventArr.push(fn)
            })
        },
        /**
         * 订阅事件一次
         * @param  {[type]}   eventName [description]
         * @param  {[type]}   fnName    [description]
         * @param  {Function} fn        [description]
         * @return {[type]}             [description]
         */
        bindOnce: function (eventName, fn) {
            var out = this
            var newFunc = function (data) {
                fn(data)
                var uid = nextUid()
                newFunc.fnName = uid
                out.unbind(eventName, uid)
            }
            this.bind(eventName, newFunc)
        }
    };
    pb.fn.$jcQueue = {}
    return pb
}
if(module){
    module.exports = initPB
}else if(window){
    window.initPB = initPB
}
